package gpfile


import (
"bytes"
"io/ioutil"
"strings"
"syscall"
)

type KVConfig interface {
	Load(path string) error
	Store(path string) error
	Get(key string) string
	Set(key, val string)
}

type myKVConfig struct {
	keys map[string]string
}

func NewKVConfig() KVConfig {
	return &myKVConfig{make(map[string]string)}
}

func NewKVConfigWithFile(path string) (c KVConfig, err error) {
	c = NewKVConfig()
	err = c.Load(path)
	return
}

func (c *myKVConfig) Load(path string) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	buf := bytes.NewBuffer(data)
	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			break
		}
		line = strings.TrimSpace(line)
		if line == "" || line[0] == '#' {
			continue
		}
		parts := strings.SplitN(line, "=", 2)
		if len(parts) == 2 {
			c.keys[parts[0]] = parts[1]
		}
	}
	return nil
}

func (c *myKVConfig) Store(path string) error {
	var buf bytes.Buffer
	for k, v := range c.keys {
		buf.WriteString(k)
		buf.WriteRune('=')
		buf.WriteString(v)
		buf.WriteRune('\n')
	}
	err := ioutil.WriteFile(path, buf.Bytes(), 0664)
	return err
}

func (c *myKVConfig) Get(key string) string {
	return c.keys[key]
}

func (c *myKVConfig) Set(key, val string) {
	c.keys[key] = val
}

type VolatileKVConfig struct {
	path string
	conf KVConfig
}

func (c *VolatileKVConfig) Load(path string) error {
	return syscall.ENOTSUP
}

func (c *VolatileKVConfig) Store(path string) error {
	if path != c.path {
		return c.conf.Store(path)
	}
	return nil
}

func (c *VolatileKVConfig) Get(key string) string {
	return c.conf.Get(key)
}

func (c *VolatileKVConfig) Set(key, val string) {
	c.conf.Set(key, val)
	c.conf.Store(c.path)
	syscall.Sync()
}

func NewVolatileKVConfig(path string) (c KVConfig, err error) {
	conf := NewKVConfig()
	err = conf.Load(path)
	if err != nil {
		return
	}
	c = &VolatileKVConfig{path, conf}
	return
}


